package com.dolphin.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dolphin.commons.Pager;
import com.dolphin.mapper.PermissionMapper;
import com.dolphin.mapper.RolePermissionMapper;
import com.dolphin.model.Permission;
import com.dolphin.model.RolePermission;
import com.dolphin.service.PermissionService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 描述:
 * ${DESCRIPTION}
 *
 * @author 林平
 * @create 2022-09-22 23:36
 * 个人博客地址：https://www.nonelonely.com
 */
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements PermissionService {
    private final static Logger LOGGER = LoggerFactory.getLogger(PermissionServiceImpl.class);

    @Autowired
    private ShiroFilterFactoryBean shiroFilterFactoryBean;

    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private RolePermissionMapper rolePermissionMapper;

    /**
     * 初始化权限
     */
    private Map loadFilterChainDefinitions() {
        // 权限控制map.
        Map filterChainDefinitionMap = new LinkedHashMap();
        //从数据库获取
        Map queryMap = new HashMap();
        queryMap.put("enable", '0');
        List<Permission> list = permissionMapper.selectByMap(queryMap);
        for (Permission permission : list) {
            filterChainDefinitionMap.put(permission.getUrl(),
                    "perms[" + permission.getPermissionValue() + "]");
        }
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/doLogin", "anon");
        filterChainDefinitionMap.put("/register", "anon");
        filterChainDefinitionMap.put("/doRegister", "anon");
        filterChainDefinitionMap.put("/restPassword", "anon");
        filterChainDefinitionMap.put("/logout", "anon");
        filterChainDefinitionMap.put("/404", "anon");
        filterChainDefinitionMap.put("/500", "anon");
        filterChainDefinitionMap.put("/403", "anon");
        filterChainDefinitionMap.put("/api/401", "anon");
        filterChainDefinitionMap.put("/install", "anon");

        return filterChainDefinitionMap;
    }

    /**
     * 更新权限
     */
    @Override
    public void updatePermission(List<Permission> permissions) {
        permissions.forEach(x -> {
            Map map = new HashMap();
            map.put("url", x.getUrl());
            List<Permission> list = permissionMapper.selectByMap(map);
            if (CollectionUtil.isNotEmpty(list)) {
                x.setId(list.get(0).getId());
                permissionMapper.updateById(x);
            } else {
                permissionMapper.insert(x);
            }

        });
        if (CollectionUtil.isNotEmpty(permissions)) {
            permissionMapper.deletePermissionByNotUrl(permissions);
        }
    }

    /**
     * 更新权限
     */
    @Override
    public void removePluginSystemPermissionList(List<Permission> permissions) {
        if (CollectionUtil.isNotEmpty(permissions)) {
            rolePermissionMapper.deleteRolePermissionByUrl(permissions);
            permissionMapper.deletePermissionByUrl(permissions);
        }
    }


    /**
     * 重新加载权限
     */
    @Override
    public void updatePermission() {
        synchronized (shiroFilterFactoryBean) {
            AbstractShiroFilter shiroFilter = null;
            try {
                shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean
                        .getObject();
            } catch (Exception e) {
                throw new RuntimeException(
                        "get ShiroFilter from shiroFilterFactoryBean error!");
            }
            PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter
                    .getFilterChainResolver();
            DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver
                    .getFilterChainManager();
            // 清空老的权限控制
            manager.getFilterChains().clear();
            shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
            shiroFilterFactoryBean
                    .setFilterChainDefinitionMap(loadFilterChainDefinitions());
            // 重新构建生成
            Map<String, String> chains = shiroFilterFactoryBean
                    .getFilterChainDefinitionMap();
            for (Map.Entry<String, String> entry : chains.entrySet()) {
                String url = entry.getKey();
                String chainDefinition = entry.getValue().trim()
                        .replace(" ", "");
                manager.createChain(url, chainDefinition);
            }
            LOGGER.info("更新权限成功！！");
        }
    }

    @Override
    public List<Permission> selectPermissionByRoleId(Long roleId) {
        return permissionMapper.selectPermissionByRoleId(roleId);
    }

    /**
     * 增加角色资源
     */
    @Override
    public void addPermissionByRoleId(RolePermission rolePermission) {
        rolePermissionMapper.insert(rolePermission);
    }

    @Override
    public int changeEnable(Permission permission) {
        return permissionMapper.changeEnable(permission);
    }

    @Override
    public Pager<Permission> list(Pager<Permission> pager) {
        PageHelper.startPage(pager.getPageIndex(), pager.getPageSize());
        QueryWrapper<Permission> userQueryWrapper = new QueryWrapper<>(pager.getForm());
        List<Permission> categories = this.list(userQueryWrapper);
        PageInfo<Permission> pageInfo = new PageInfo<>(categories);
        pager.setTotal(pageInfo.getTotal());
        pager.setData(pageInfo.getList());
        pager.setCode(Pager.SUCCESS_CODE);
        return pager;
    }
}
